home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Examples / Scrolling Demo / Scrolling Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  24.1 KB  |  859 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // Scrolling Demo.c
  3. //
  4. // By Vern Jensen. Created in August of 1995
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11. #include <SWStats.h>
  12. #include <SWParticles.h>
  13. #include <SWApplication.h>
  14.  
  15. #include "Scrolling Demo.h"
  16.  
  17.  
  18. #define    kFullScreenWindow            true        // Try me full screen!
  19. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  20. #define    kInterlacedMode                false        // Skips every other line
  21. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  22. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  23.  
  24. #define kDoParticleExplosion        true        // Allows you to turn particle effects on/off    
  25.  
  26. #define kNumParticles                3500        // Max number of particles
  27. #define kGravity         SW_FLOAT2FIX(.8)        // Gravity applied to each particle
  28. #define kExplosionLifeRemaining        60            // How long the particles last
  29.  
  30.  
  31. #define    kSpriteMoveDelta            20            // Try 5, 10, 20, or 40
  32. #define kDiamondSpace                8            // How far apart the diamonds are spaced
  33.                                                 // (try 1!)
  34.  
  35. #define kSpriteMoveDistance            80            // How far the sprite can move from
  36.                                                 // the center of the screen, in pixels.
  37.                                                 // Try making this value higher!
  38.  
  39. #define kStatsOffset                85            // Distance the numbers are from the right side
  40.                                                 // of the screen.
  41.  
  42.     // Number of ticks to wait before changing tile image; 0 = change every frame
  43. #define kDiamondFrameRate            8            // How often diamond tiles change frames
  44. #define kWallFrameRate                120            // How often wall changes frames
  45.  
  46. #define kBWPictResIDOffset            100
  47. #define kTileWidth                    40
  48. #define kTileHeight                    40
  49. #define kTileMapRows                100
  50. #define kTileMapCols                150
  51.  
  52. #define kStartRow                    5            // Starting position of sprite
  53. #define kStartCol                    5            // in tile col and row
  54.  
  55.  
  56. #define    kLeftArrowKey                0x7B
  57. #define    kRightArrowKey                0x7C
  58. #define    kDownArrowKey                0x7D
  59. #define    kUpArrowKey                    0x7E
  60.  
  61. #define    kLeftKeyPad                    0x56
  62. #define    kRightKeyPad                0x58
  63. #define    kDownKeyPad                    0x54
  64. #define    kUpKeyPad                    0x5B
  65.  
  66. #define kEscKey                        0x35
  67.  
  68.  
  69. #define kNoKey                        0
  70. #define kLeftKey                    1
  71. #define kUpKey                        2
  72. #define kRightKey                    3
  73. #define kDownKey                    4
  74.  
  75.  
  76. enum tileIDs
  77. {
  78.     kWallTile,
  79.     kLastWallTile,
  80.     kGrassTile,
  81.     kBlackTile,
  82.     kDiamondTile,
  83.     kDiamondTile2,
  84.     kLastDiamondTile,
  85.     
  86.     kTunnelTile1,
  87.     kTunnelTile2,
  88.     kTunnelTile3,
  89.     kTunnelTile4,
  90.     kTunnelTile5,
  91.     kTunnelTile6,
  92.     kWireTile1,
  93.     kWireTile2,
  94.     
  95.     kMaxNumTiles
  96. };
  97.  
  98.  
  99.  
  100. /***********/
  101. /* Globals */
  102. /***********/
  103.  
  104. SpriteWorldPtr        gSpriteWorldP;
  105. SpriteLayerPtr        gSpriteLayerP, gNonScrollingSpriteLayerP;
  106. TileMapStructPtr    gTileMapStructP;
  107. TileMapPtr            gTileMap;
  108. SpritePtr            gSimpleSpriteP, gStatsSpriteP, gDiamondMeterSpriteP, gMasterStatsSpriteP;
  109. DrawProcPtr            gSpriteDrawProc;
  110. WindowPtr            gWindowP;
  111. Rect                gScreenMidRect;
  112.  
  113. long                gNumDiamondsInMap = 0;    // Number of diamonds in the TileMap
  114. long                gNumDiamonds = 0;        // Number of diamonds sprite has collected
  115.  
  116. struct moveKeys        // Keeps track of which keys are up and which are down
  117. {
  118.     Boolean    up;
  119.     Boolean    right;
  120.     Boolean    down;
  121.     Boolean    left;
  122. } gKeys;
  123.  
  124.  
  125. ///--------------------------------------------------------------------------------------
  126. // Main
  127. ///--------------------------------------------------------------------------------------
  128.  
  129. void    main( void )
  130. {
  131.     Initialize(kNumberOfMoreMastersCalls);
  132.  
  133.     if (SWHasSystem7())
  134.     {
  135.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  136.         SetCursor(*GetCursor(watchCursor));
  137.         HideControlStrip();
  138.         SWSetCleanUpFunction(MyCleanUpFunction);
  139.         
  140.         CreateSpriteWorld();
  141.         SetUpTiling();
  142.         CreateBallSprite();
  143.         CreateDiamondMeterSprite();
  144.         CreateStatsNumberSprite();
  145.         
  146.         SetCursor(&qd.arrow);
  147.         HideCursor();
  148.         
  149.         SetUpAnimation();
  150.         RunAnimation();
  151.         ShutDown();
  152.         
  153.         RestoreControlStrip();    // Call this after using HideControlStrip before quitting
  154.         RestoreEventMask();        // Call this after using AllowKeyUpEvents before quitting
  155.     }
  156.     else
  157.     {
  158.         CantRunOnThisMachine();
  159.     }
  160. }
  161.  
  162.  
  163. ///--------------------------------------------------------------------------------------
  164. // CreateSpriteWorld
  165. ///--------------------------------------------------------------------------------------
  166.  
  167. void    CreateSpriteWorld( void )
  168. {
  169.     Rect        offscreenRect, worldRect, windRect;
  170.     RgnHandle    mBarUpdateRgn;
  171.     OSErr        err;
  172.     
  173.     gWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  174.     
  175.     if (gWindowP != NULL)
  176.     {
  177.         if (kFullScreenWindow == true)
  178.         {
  179.             SizeWindow(gWindowP, qd.screenBits.bounds.right, 
  180.                     qd.screenBits.bounds.bottom, false);
  181.             MoveWindow(gWindowP, 0, 0, false);
  182.         }
  183.         else
  184.         {
  185.                 // Center window in screen
  186.             windRect = gWindowP->portRect;
  187.             CenterRect(&windRect, &qd.screenBits.bounds);
  188.             
  189.                 // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  190.             windRect.left = windRect.left>>2<<2;
  191.             
  192.             MoveWindow(gWindowP, windRect.left, windRect.top, false);
  193.         }
  194.         
  195.         ShowWindow(gWindowP);
  196.         SetPort(gWindowP);
  197.         mBarUpdateRgn = SWHideMenuBar(gWindowP); // Must be done *after* showing window!
  198.         EraseRgn(mBarUpdateRgn);
  199.         
  200.         if (kInterlacedMode)
  201.             PaintRect(&gWindowP->portRect);    // Blacken window for Interlaced mode
  202.     }
  203.     else
  204.         CantFindResource();
  205.     
  206.     
  207.     err = SWEnterSpriteWorld();
  208.     FatalError(err);
  209.     
  210.     
  211.     worldRect = gWindowP->portRect;
  212.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  213.     
  214.     
  215.         // Set size of offscreen area
  216.     offscreenRect = worldRect;
  217.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  218.     
  219.  
  220.         // Make offscreen area evenly divisible by tile width & height
  221.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  222.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  223.     
  224.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  225.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  226.     
  227.         // Create the scrolling sprite world
  228.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  229.             &worldRect, &offscreenRect, 0);
  230.     FatalError(err);
  231.     
  232.         // Create the sprite layers
  233.     err = SWCreateSpriteLayer(&gSpriteLayerP);
  234.     FatalError(err);
  235.     err = SWCreateSpriteLayer(&gNonScrollingSpriteLayerP);
  236.     FatalError(err);
  237.     
  238.         // Add them to the world
  239.     SWAddSpriteLayer(gSpriteWorldP, gSpriteLayerP);                    // Bottom
  240.     SWAddSpriteLayer(gSpriteWorldP, gNonScrollingSpriteLayerP);        // Top
  241.     
  242.     
  243.     gSpriteDrawProc = SWStdSpriteDrawProc;
  244.     
  245.         // Determine what DrawProcs to use
  246.     if (gSpriteWorldP->pixelDepth >= 8)        // 8-bit, 16-bit, or 32-bit, for 68k and PPC
  247.     {
  248.         gSpriteDrawProc = BlitPixieMaskDrawProc;
  249.         SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieRectDrawProc);
  250.         SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixieDoubleRectDrawProc);
  251.         SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixiePartialMaskDrawProc);
  252.     }
  253.     else if ( SW_68K )    // Use the 68k-only AllBit blitters for depths below 8-bits.
  254.     {
  255.         gSpriteDrawProc = BlitPixieAllBitMaskDrawProc;
  256.         SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  257.         SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  258.         SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  259.     }
  260. }
  261.  
  262.  
  263. ///--------------------------------------------------------------------------------------
  264. // SetUpTiling
  265. ///--------------------------------------------------------------------------------------
  266.  
  267. void    SetUpTiling( void )    
  268. {
  269.     short        resIDOffset;
  270.     short        row, col;
  271.     OSErr        err;
  272.  
  273.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  274.     FatalError(err);
  275.     
  276.     err = SWCreateTileMap(&gTileMapStructP, kTileMapRows, kTileMapCols);
  277.     FatalError(err);
  278.     
  279.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  280.     gTileMap = gTileMapStructP->tileMap;
  281.     
  282.     SWSetSpriteLayerUnderTileLayer(gSpriteLayerP, 0);
  283.     
  284.  
  285.         // Determine whether to load B&W or color graphics
  286.     if (gSpriteWorldP->pixelDepth <= 2)
  287.         resIDOffset = kBWPictResIDOffset;
  288.     else
  289.         resIDOffset = 0;
  290.  
  291.         // Load first set of tiles
  292.     err = SWLoadTilesFromPictResource(
  293.         gSpriteWorldP, 
  294.         kWallTile,                // startTileID 
  295.         kLastDiamondTile,        // endTileID
  296.         200 + resIDOffset,        // pictResID
  297.         0,                        // maskResID
  298.         kNoMask,                // maskType
  299.         kMaskIsNotPartialMask,    // partialMask?
  300.         1,                        // horizBorderWidth
  301.         1);                        // vertBorderHeight
  302.     FatalError(err);
  303.     
  304.         // Load masked set of tiles
  305.     err = SWLoadTilesFromPictResource(
  306.         gSpriteWorldP, 
  307.         kTunnelTile1,            // startTileID 
  308.         kWireTile2,                // endTileID
  309.         201 + resIDOffset,        // pictResID
  310.         401,                    // maskResID
  311.         kFatMask,                // maskType
  312.         kMaskIsPartialMask,        // partialMask?
  313.         1,                        // horizBorderWidth
  314.         1);                        // vertBorderHeight
  315.     FatalError(err);
  316.  
  317.     
  318.         // Set up tileMap
  319.     for (row = 0; row < kTileMapRows; row++)
  320.     {
  321.         for (col = 0; col < kTileMapCols; col++)
  322.         {
  323.             if (row == 0 || col == 0 || row == kTileMapRows-1 || col == kTileMapCols-1)
  324.                 gTileMap[row][col] = kWallTile;
  325.             else if (row > kTileMapRows / 2)
  326.                 gTileMap[row][col] = kWireTile1;
  327.             else if ((row/kDiamondSpace)*kDiamondSpace == row && 
  328.                      (col/kDiamondSpace)*kDiamondSpace == col)
  329.             {
  330.                 gTileMap[row][col] = kDiamondTile;
  331.                 gNumDiamondsInMap++;
  332.             }
  333.             else
  334.                 gTileMap[row][col] = kGrassTile;
  335.         }
  336.     }
  337.     
  338.  
  339.         // Add tunnel to tileMap
  340.     row = kTileMapRows / 2;
  341.  
  342.     for (col = 1; col < kTileMapCols-1; col += 2)
  343.     {
  344.         gTileMap[row][col] = kTunnelTile1;
  345.         gTileMap[row][col+1] = kTunnelTile2;
  346.         gTileMap[row+1][col] = kTunnelTile4;
  347.         gTileMap[row+1][col+1] = kTunnelTile5;
  348.     }
  349. }
  350.  
  351.  
  352. ///--------------------------------------------------------------------------------------
  353. // CreateBallSprite
  354. ///--------------------------------------------------------------------------------------
  355.  
  356. void    CreateBallSprite( void )
  357. {
  358.     OSErr    err;
  359.     
  360.         // Create the ball sprite
  361.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSimpleSpriteP, NULL, 
  362.             128, 1, kFatMask);    
  363.     FatalError(err);
  364.     
  365.         // Set up the ball sprite
  366.     SWAddSprite(gSpriteLayerP, gSimpleSpriteP);
  367.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  368.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  369.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  370.     SWSetSpriteDrawProc(gSimpleSpriteP, gSpriteDrawProc);
  371. }
  372.  
  373.  
  374. ///--------------------------------------------------------------------------------------
  375. // CreateDiamondMeterSprite
  376. ///--------------------------------------------------------------------------------------
  377.  
  378. void    CreateDiamondMeterSprite( void )
  379. {
  380.     short        spriteResID;
  381.     OSErr        err;
  382.     
  383.         // Calculate resource ID for diamond meter sprite
  384.     if (gSpriteWorldP->pixelDepth <= 2)
  385.         spriteResID = 302;
  386.     else
  387.         spriteResID = 202;
  388.     
  389.         // Create the diamond meter sprite
  390.     err = SWCreateSpriteFromPictResource(gSpriteWorldP,
  391.                 &gDiamondMeterSpriteP, 
  392.                 NULL,            // pointer to memory for sprite
  393.                 spriteResID,     // picture resource id
  394.                 402,            // mask resource id
  395.                 1,                 // max frames
  396.                 kFatMask);        // mask type            
  397.     FatalError(err);
  398.     
  399.     SWAddSprite(gNonScrollingSpriteLayerP, gDiamondMeterSpriteP);
  400.     SWSetSpriteDrawProc(gDiamondMeterSpriteP, gSpriteDrawProc);    
  401.     SWSetSpriteMoveProc(gDiamondMeterSpriteP, DiamondMeterSpriteMoveProc);
  402.     SWSetSpriteLocation(gDiamondMeterSpriteP, 10, 10);
  403.     
  404.         // Mark this layer as a non-scrolling layer
  405.     SWSetLayerAsNonScrolling(gNonScrollingSpriteLayerP, true);
  406. }
  407.  
  408.  
  409. ///--------------------------------------------------------------------------------------
  410. // CreateStatsNumberSprite
  411. ///--------------------------------------------------------------------------------------
  412.  
  413. void    CreateStatsNumberSprite( void )
  414. {
  415.     OSErr        err;
  416.     
  417.         // Load gMasterStatsSpriteP
  418.     err = SWCreateSpriteFromSinglePict(gSpriteWorldP, &gMasterStatsSpriteP, 
  419.             NULL, 128, 128, 24, 0, kFatMask);
  420.     FatalError(err);
  421.     
  422.     SWLockSprite(gMasterStatsSpriteP);
  423.     
  424.         // Create the gNumLivesStatsSpriteP
  425.     gStatsSpriteP = CreateStatsSpriteClone(gMasterStatsSpriteP, 3, kRightJustify, false);
  426.     err = SetUpStatsSprite(gStatsSpriteP, gNonScrollingSpriteLayerP, gSpriteDrawProc,
  427.             gSpriteWorldP->windRect.right - kStatsOffset, 8, 0);
  428.     FatalError(err);
  429.     
  430.     SWSetSpriteMoveProc(gStatsSpriteP, StatsSpriteMoveProc);
  431. }
  432.  
  433.  
  434. ///--------------------------------------------------------------------------------------
  435. // SetUpAnimation
  436. ///--------------------------------------------------------------------------------------
  437.  
  438. void    SetUpAnimation( void )
  439. {
  440.     Rect        moveBoundsRect;
  441.     OSErr        err;
  442.     
  443.     SWLockSpriteWorld(gSpriteWorldP);
  444.     
  445.         // Set up data used by the SmoothScrollingWorldMoveProc
  446.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  447.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  448.     
  449.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  450.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  451.     SWSetCleanUpSpriteWorld(gSpriteWorldP);
  452.     
  453.     if (gSpriteWorldP->pixelDepth >= 8)
  454.     {
  455.             // Set up particle stuff
  456.         err = InitParticles(kNumParticles, kGravity);
  457.         FatalError(err);
  458.         
  459.         SWSetPostEraseCallBack(gSpriteWorldP, EraseParticlesScrollingOffscreen);
  460.         SWSetPostDrawCallBack(gSpriteWorldP, DrawParticlesScrollingOffscreen);
  461.     }
  462.     
  463.         // movement boundary = size of tileMap
  464.     SetRect(&moveBoundsRect, 0,0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  465.     
  466.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  467.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  468.     
  469.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  470.     
  471.         // Move visScrollRect to starting sprite position
  472.     SWMoveVisScrollRect(gSpriteWorldP, 
  473.         SWGetSpriteHorizLoc(gSpriteWorldP->followSpriteP) - gSpriteWorldP->backRect.right/2,
  474.         SWGetSpriteVertLoc(gSpriteWorldP->followSpriteP) - gSpriteWorldP->backRect.bottom/2);
  475.     
  476.         // Make sure CopyBits, if used, doesn't try to colorize things
  477.     SWSetPortToWindow(gSpriteWorldP);
  478.     ForeColor(blackColor);
  479.     BackColor(whiteColor);
  480.     
  481.     if (kInterlacedMode)
  482.     {
  483.         SWSetFrameInterlacingMode(gSpriteWorldP->workFrameP, true, kSkipOddLines);
  484.         SWSetFrameInterlacingMode(gSpriteWorldP->windowFrameP, true, kSkipOddLines);
  485.         
  486.         SWSetPortToWorkArea(gSpriteWorldP);
  487.         PaintRect(&gSpriteWorldP->backRect);
  488.     }
  489.     
  490.     SWDrawTilesInBackground(gSpriteWorldP);
  491.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  492. }
  493.  
  494.  
  495. ///--------------------------------------------------------------------------------------
  496. //  RunAnimation
  497. ///--------------------------------------------------------------------------------------
  498.  
  499. void    RunAnimation( void )
  500. {
  501.     unsigned long        frames;
  502.         
  503.     frames = 0;
  504.     StartTimer();
  505.  
  506.     FatalError( SWStickyError() ); // Make sure no errors got past us during setup
  507.  
  508.     while (!Button())
  509.     {
  510.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  511.         FatalError( SWStickyError() );    // Make sure no errors occurred during a MoveProc, etc.
  512.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  513.         
  514.         SetStatsSpriteNumber(gStatsSpriteP, gNumDiamonds);
  515.         
  516.         if (gSpriteWorldP->frameHasOccurred)
  517.         {
  518.             if (gSpriteWorldP->pixelDepth >= 8)
  519.                 UpdateParticlesInScrollingWindow(gSpriteWorldP);
  520.             
  521.             frames++;
  522.         }
  523.     }
  524.     
  525.     
  526.     SWShowMenuBar(gWindowP);
  527.     ShowResults(frames);
  528. }
  529.  
  530.  
  531. #pragma mark -
  532. ///--------------------------------------------------------------------------------------
  533. //  ShutDown (clean up and dispose of the SpriteWorld)
  534. ///--------------------------------------------------------------------------------------
  535.  
  536. void    ShutDown( void )
  537. {
  538.     SWDisposeSprite(&gMasterStatsSpriteP);
  539.     SWDisposeSpriteWorld(&gSpriteWorldP);
  540.     SWExitSpriteWorld();
  541.     
  542.     FlushEvents(everyEvent, 0);
  543.     InitCursor();
  544. }
  545.  
  546.  
  547. ///--------------------------------------------------------------------------------------
  548. //  MyCleanUpFunction - called if an error occurs, to clean up before quitting
  549. ///--------------------------------------------------------------------------------------
  550.  
  551. void    MyCleanUpFunction( void )
  552. {
  553.     SWShowMenuBar(gWindowP);
  554.     
  555.     RestoreControlStrip();
  556.     RestoreEventMask();    
  557. }
  558.  
  559.  
  560. ///--------------------------------------------------------------------------------------
  561. //  TileChangeProc
  562. ///--------------------------------------------------------------------------------------
  563.  
  564. SW_FUNC void TileChangeProc(
  565.     SpriteWorldPtr spriteWorldP)
  566. {
  567.     short            curImage;
  568.     static short    wallDelay = 0, diamondDelay = 0;
  569.     static short    oldTicks = 0;
  570.     short            ticksPassed, ticks;
  571.     
  572.         // Initialize oldTicks the first time this function is called
  573.     if (oldTicks == 0)
  574.         oldTicks = TickCount();
  575.     
  576.     ticks = TickCount();
  577.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  578.     oldTicks = ticks;
  579.     
  580.         // kWallTile
  581.     wallDelay += ticksPassed;
  582.     if (wallDelay >= kWallFrameRate)
  583.     {
  584.         curImage = spriteWorldP->curTileImage[kWallTile];
  585.         if (curImage < kLastWallTile)
  586.             curImage++;
  587.         else
  588.             curImage = kWallTile;
  589.         
  590.         SWChangeTileImage(spriteWorldP, kWallTile, curImage);
  591.         wallDelay = 0;
  592.     }
  593.     
  594.     
  595.         // kDiamondTile
  596.     diamondDelay += ticksPassed;
  597.     if (diamondDelay >= kDiamondFrameRate)
  598.     {
  599.         curImage = spriteWorldP->curTileImage[kDiamondTile];
  600.         if (curImage < kLastDiamondTile)
  601.             curImage++;
  602.         else
  603.             curImage = kDiamondTile;
  604.         
  605.         SWChangeTileImage(spriteWorldP, kDiamondTile, curImage);
  606.         diamondDelay = 0;
  607.     }
  608. }
  609.  
  610.  
  611. ///--------------------------------------------------------------------------------------
  612. //  KeySpriteMoveProc
  613. ///--------------------------------------------------------------------------------------
  614.  
  615. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  616. {
  617.     short    row, col;
  618.     short    rowDelta, colDelta;
  619.     short    tile;
  620.     
  621.     UpdateKeys();    // Put the latest key values in the keys structure
  622.     
  623.     
  624.     row = SWGetSpriteVertLoc(srcSpriteP) / kTileHeight;
  625.     col = SWGetSpriteHorizLoc(srcSpriteP) / kTileWidth;
  626.  
  627.     if (row * kTileHeight == SWGetSpriteVertLoc(srcSpriteP) &&
  628.         col * kTileWidth == SWGetSpriteHorizLoc(srcSpriteP))
  629.     {
  630.         tile = gTileMap[row][col];
  631.         
  632.             // Leave black trail behind sprite
  633.         if (tile == kGrassTile || tile == kDiamondTile)
  634.             SWDrawTile(gSpriteWorldP, 0, row, col, kBlackTile);
  635.         else if (tile == kTunnelTile2 || tile == kTunnelTile5 || tile == kWireTile1)
  636.             SWDrawTile(gSpriteWorldP, 0, row, col, tile+1);
  637.             
  638.         if (tile == kDiamondTile)
  639.         {
  640.             gNumDiamonds++;            // Increase number of diamonds sprite has collected
  641.             UpdateDiamondMeter();    // Update meter
  642.             
  643.             if (kDoParticleExplosion && gSpriteWorldP->pixelDepth >= 8)
  644.                 DoParticleExplosionForTile(row, col, tile);
  645.         }
  646.         
  647.  
  648.         rowDelta = 0;
  649.         colDelta = 0;
  650.         
  651.         if (gKeys.left)
  652.             colDelta = -1;
  653.         else if (gKeys.right)
  654.             colDelta = 1;
  655.         else if (gKeys.up)
  656.             rowDelta = -1;
  657.         else if (gKeys.down)
  658.             rowDelta = 1;
  659.         
  660.                 
  661.         
  662.         tile = gTileMap[row + rowDelta][col + colDelta];
  663.         
  664.         if (tile != kWallTile && tile != kTunnelTile1 && tile != kTunnelTile4)
  665.         {
  666.             srcSpriteP->vertMoveDelta = rowDelta * kSpriteMoveDelta;
  667.             srcSpriteP->horizMoveDelta = colDelta * kSpriteMoveDelta;
  668.         }
  669.         else
  670.         {
  671.             srcSpriteP->vertMoveDelta = 0;
  672.             srcSpriteP->horizMoveDelta = 0;
  673.         }
  674.     }
  675.     
  676.     SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  677.     srcSpriteP->needsToBeDrawn = true;    // Otherwise the particles will erase parts of our sprite when it is idle
  678. }
  679.  
  680.  
  681. ///--------------------------------------------------------------------------------------
  682. //  DiamondMeterSpriteMoveProc
  683. ///--------------------------------------------------------------------------------------
  684.  
  685. SW_FUNC void DiamondMeterSpriteMoveProc(SpritePtr srcSpriteP)
  686. {
  687.     SWMoveSprite(srcSpriteP, 
  688.         10 + gSpriteWorldP->visScrollRect.left, 
  689.         10 + gSpriteWorldP->visScrollRect.top);
  690. }
  691.  
  692.  
  693. ///--------------------------------------------------------------------------------------
  694. //  StatsSpriteMoveProc
  695. ///--------------------------------------------------------------------------------------
  696.  
  697. SW_FUNC void StatsSpriteMoveProc(SpritePtr srcSpriteP)
  698. {
  699.     SWMoveSprite(srcSpriteP, 
  700.         gSpriteWorldP->windRect.right - kStatsOffset + gSpriteWorldP->visScrollRect.left, 
  701.         8 + gSpriteWorldP->visScrollRect.top);
  702. }
  703.  
  704.  
  705. ///--------------------------------------------------------------------------------------
  706. //  UpdateDiamondMeter - change the meter Sprite's image and mask
  707. ///--------------------------------------------------------------------------------------
  708.  
  709. SW_FUNC void UpdateDiamondMeter( void )
  710. {
  711.     double    percent;
  712.     Rect    meterRect;
  713.     
  714.     percent = (double)gNumDiamonds / gNumDiamondsInMap;
  715.     
  716.         // 108 = length of meter; 17 = offset from start of meter
  717.     SetRect(&meterRect, 17, 2, (108 * percent) + 17, 14);
  718.     
  719.     
  720.         // Set port to our sprite's framePort GWorld
  721.     SetGWorld(gDiamondMeterSpriteP->curFrameP->framePort, nil);
  722.     
  723.     ForeColor(magentaColor);
  724.     PaintRect(&meterRect);
  725.     
  726.         // IMPORTANT: Set the color back when done! (In case CopyBits is used later)
  727.     ForeColor(blackColor);
  728.     
  729.  
  730.         // Update the pixel mask directly if we are using a pixelMask.
  731.     if (gDiamondMeterSpriteP->frameDrawProc != SWStdSpriteDrawProc)
  732.     {
  733.             // Set port to our sprite's pixel mask GWorld
  734.         SetGWorld(gDiamondMeterSpriteP->curFrameP->maskPort, nil);
  735.         
  736.             // Mask image is inverted when in 8-bit or less
  737.         if (gSpriteWorldP->pixelDepth <= 8)
  738.             ForeColor(whiteColor);
  739.         else
  740.             ForeColor(blackColor);
  741.         
  742.         PaintRect(&meterRect);
  743.         ForeColor(blackColor);
  744.     }
  745.     else
  746.     {
  747.             // Otherwise, use SWUpdateFrameMasks to update the region mask.
  748.         SWUpdateFrameMasks(gDiamondMeterSpriteP->curFrameP);
  749.     }
  750.     
  751.     
  752.         // Set sprite to be redrawn, since we've changed its image
  753.     gDiamondMeterSpriteP->needsToBeDrawn = true;
  754. }
  755.  
  756.  
  757. ///--------------------------------------------------------------------------------------
  758. //  DoParticleExplosionForTile - turns each non-black pixel of a tile into a particle
  759. ///--------------------------------------------------------------------------------------
  760.  
  761. void DoParticleExplosionForTile(
  762.     short tileRow, 
  763.     short tileCol, 
  764.     short tileID)
  765. {    
  766.     FramePtr        tileFrameP;
  767.     short            row, col, pixelRow, pixelCol;
  768.     unsigned long    color, black;
  769.     float            hDelta, vDelta;
  770.     short            halfWidth, halfHeight;
  771.     RGBColor        blackRGB = {0,0,0};
  772.     
  773.     black = Color2Index( &blackRGB );
  774.     
  775.         // Get the FrameP for the tile at tileRow and tileCol
  776.     tileFrameP = gSpriteWorldP->tileFrameArray[ gSpriteWorldP->curTileImage[tileID] ];
  777.     SWSetPortToFrame(tileFrameP);
  778.     
  779.     pixelRow = tileRow * gSpriteWorldP->tileHeight;
  780.     pixelCol = tileCol * gSpriteWorldP->tileWidth;
  781.     
  782.     halfWidth = (tileFrameP->frameRect.right - tileFrameP->frameRect.left) / 2;
  783.     halfHeight = (tileFrameP->frameRect.bottom - tileFrameP->frameRect.top) / 2;
  784.     
  785.     for (row = tileFrameP->frameRect.top; row < tileFrameP->frameRect.bottom; row++)
  786.         for (col = tileFrameP->frameRect.left; col < tileFrameP->frameRect.right; col++)
  787.         {
  788.             color = SWGetPixel(tileFrameP, col, row);
  789.             
  790.             if (color != black)
  791.             {
  792.                 hDelta = (float)((col - tileFrameP->frameRect.left) - halfWidth) / 6;
  793.                 vDelta = (float)((row - tileFrameP->frameRect.top) - halfHeight) / 6 - 8;
  794.                 
  795.                 NewParticle( 
  796.                     color, 
  797.                     SW_INT2FIX(pixelCol + col - tileFrameP->frameRect.left),
  798.                     SW_INT2FIX(pixelRow + row - tileFrameP->frameRect.top),
  799.                     SW_FLOAT2FIX(hDelta),
  800.                     SW_FLOAT2FIX(vDelta),
  801.                     kExplosionLifeRemaining);
  802.             }
  803.         }
  804. }
  805.  
  806.  
  807. ///--------------------------------------------------------------------------------------
  808. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  809. ///--------------------------------------------------------------------------------------
  810.  
  811. SW_FUNC void SmoothScrollingWorldMoveProc(
  812.     SpriteWorldPtr spriteWorldP,
  813.     SpritePtr followSpriteP)
  814. {    
  815.     short    screenMidRectTop, screenMidRectLeft;
  816.     
  817.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  818.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  819.     
  820.     
  821.     spriteWorldP->horizScrollDelta = (kSpriteMoveDelta * 
  822.         (SWGetSpriteHorizLoc(followSpriteP) - screenMidRectLeft) ) / kSpriteMoveDistance;
  823.         
  824.         
  825.     
  826.     spriteWorldP->vertScrollDelta = (kSpriteMoveDelta * 
  827.         (SWGetSpriteVertLoc(followSpriteP) - screenMidRectTop) ) / kSpriteMoveDistance;
  828.     
  829.     if (kInterlacedMode)
  830.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  831. }
  832.  
  833.  
  834. ///--------------------------------------------------------------------------------------
  835. //  UpdateKeys (Put the latest key values in the keys structure)
  836. ///--------------------------------------------------------------------------------------
  837.  
  838. void    UpdateKeys( void )
  839. {
  840.     EventRecord        event;
  841.     short            theKey;
  842.     Boolean            isDown;
  843.     
  844.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  845.     {
  846.         theKey = (event.message & keyCodeMask) >> 8;
  847.         isDown = (event.what != keyUp);
  848.         
  849.         if ( (theKey == kLeftArrowKey) || (theKey == kLeftKeyPad) )
  850.             gKeys.left = isDown;
  851.         else if ( (theKey == kRightArrowKey) || (theKey == kRightKeyPad) )
  852.             gKeys.right = isDown;
  853.         else if ( (theKey == kDownArrowKey) || (theKey == kDownKeyPad) )
  854.             gKeys.down = isDown;
  855.         else if ( (theKey == kUpArrowKey) || (theKey == kUpKeyPad) )
  856.             gKeys.up = isDown;
  857.     }
  858. }
  859.